package networking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import networking.answerers.ClassifyAnswerer;
import networking.answerers.GetParamsAnswerer;
import networking.answerers.ServerErrorAnswerer;

import perceptron.Classifier;
import perceptron.ClassifierLoader;
import perceptron.ClassifiersBuffer;
import preprocess.RegexpTools;


/**
 * Cette classe gère la communication avec le plugin.
 * @param arg
 */
public class Communicator {
	
	/**
	 * Port sur lequel le serveur écoute et attend qu'un plugin chrome se manifeste (par défaut 55666)
	 */
	private int port ;
	
	/**
	 * Liste des noms des classifiers connus par le Communicator.
	 */
	private ArrayList<String> names ;
	
	/**
	 * Le buffer chargeant classifieurs.
	 */
	private ClassifiersBuffer buffer;
	
	
	/**
	 * Constructeur
	 * @throws IOException 
	 */
	public Communicator(int port, String[] paths, int maxClass) throws IOException {
		
		this.port = port ;
		names = new ArrayList<String>(paths.length) ;
		for(int i=0 ; i<paths.length ; i++) {
			names.add(ClassifierLoader.load(paths[i]).getName()) ;
		}
		this.buffer=new ClassifiersBuffer(maxClass,paths) ;
		
	}
	
	/**
	 * Expédier une réponse sur un socket donnée;
	 */
	public void send(PrintStream out, String m) {
		
		out.println("HTTP/1.1"+" 200 OK") ;
		out.println() ;
		out.println(m) ;
		
	}
	
	/**
	 * Lancer le serveur
	 * @throws IOException 
	 */
	public void start() throws IOException {
		
		/* Création du socket d'écoute les demandes d'un plugin chrome */
		ServerSocket ss = new ServerSocket(port) ;
		
		while(true) {
			
			/* Attente d'une requête */
			Socket connexion = ss.accept() ;
			
			/* Récuperation du reader et du writer */
			BufferedReader in = new BufferedReader(new InputStreamReader(connexion.getInputStream()));
			PrintStream out = new PrintStream(connexion.getOutputStream());
		
			/* Lire la requête */
			String line = in.readLine() ;
			System.out.println("Reception d'une requête : " + line);
			
			/* Récuperer les différent éléments de la requète. */
			StringTokenizer st = new StringTokenizer(line) ;
			String cmd="", arg="",ver="" ;
			cmd = st.nextToken() ;
			arg = st.nextToken() ;
			ver = st.nextToken() ;
			
			/* Regarder de quel type de requête il s'agit */
			String requestType = RegexpTools.getValue(arg,"type") ;
			if(requestType!=null) {
				
				if(requestType.equals("getParams")) { /* Demande des paramètre du serveur */
					send(out,GetParamsAnswerer.generate(names)) ;
					
				} else if(requestType.equals("classify")) { /* Demande de traitement d'une page.
				
					/* Lire l'adresse de la page demandée */
					String adress = RegexpTools.getValue(arg,"adress") ;
					/* Lire l'id du classifier choisi pas l'utilisateur */
					int id = Integer.parseInt(RegexpTools.getValue(arg,"id")) ;
					
					/* Verifier l'id */
					if(id<0 || id>=names.size()) {
						send(out,ServerErrorAnswerer.generate(3,"Bad classifier id")) ;
					}
					/* Effectuer le traitement et envoyer la reponse */
					try {
						String resultXML = ClassifyAnswerer.generate(buffer.getClassifier(id),adress) ;
						send(out,resultXML) ;
					} catch (IOException e) {
						send(out,ServerErrorAnswerer.generate(3,"can't download page "+adress)) ;
					}
					
				} else {
					send(out,ServerErrorAnswerer.generate(2,"unknown request type")) ;
				}
				
			} else { /* Pas de champ type */
				send(out,ServerErrorAnswerer.generate(1,"missing request type.")) ;
			}
			
		
			connexion.close() ;
			
		}
		
	}
	
	/**
	 * Test
	 * @throws IOException 
	 * 
	 */
	public static void main(String[] args) throws IOException {
		Communicator s = new Communicator(55666,new String[]{"data/wiki1/per"},3) ;
		s.start() ;
	}

}
